#include "sersocket.h"
#include <iostream>
#include <QThread>
#include <QSoundEffect>

//将数据与命令编码成发送包
QByteArray data_encoder(QByteArray data,uint16_t cmd)
{
    QByteArray package;
    package.resize(5);
    package[0] = 0x5A;
    package[1] = (cmd >> 8) & 0xFF;
    package[2] =  cmd & 0xFF;
    package[3] = (((uint16_t)data.size()) >> 8) & 0xFF;
    package[4] = ((uint16_t)data.size()) & 0xFF;
    package.append(data);
    package.append(0xA5);
    return package;
}
//发送包解码成命令和数据
void data_decoder(QByteArray package,uint16_t& cmd,QByteArray& data)
{
    if(uint8_t(package[0]) == 0x5A)
    {
        cmd = ((((uint16_t)package[1]) << 8) & 0xFF00) + (((uint16_t)package[2]) & 0x00FF);
        int sz = (package[3]<<8)+package[4];
        data = package.remove(0,5);
        data.chop(1);
    }
}

SerSocket::SerSocket(QObject *parent)
    : QTcpSocket(parent)
{
    //收到了TCP服务的数据
    QObject::connect(this, &QIODevice::readyRead, this, &SerSocket::on_readyread, Qt::DirectConnection);
    connect(this,&SerSocket::sentfile,this,&SerSocket::on_sentfile,Qt::QueuedConnection);
    connect(this,&SerSocket::sentfiler,this,&SerSocket::on_sentfilebag,Qt::QueuedConnection);
    connect(this,&SerSocket::sentRcvRequese,this,&SerSocket::ClientSendingText,Qt::QueuedConnection);
    setReadBufferSize(16*1024*1024);

    effect=new QSoundEffect();
    effect->setSource(QUrl::fromLocalFile(":/new/prefix1/wav/dididi.wav"));
    effect->setVolume(1.0f);
}
SerSocket::~SerSocket()
{
    delete rfile;
    delete file;
}

//收到信息
void SerSocket::on_readyread()
{
    QByteArray package = this->readAll();
    if(has_last){
        qDebug()<<"duan\n";
        package.append(lastbuffer);
    }
    qDebug()<<package.toHex(' ')<<"\n";
    //    for(int i=0;i<package.size();i++)
    //        printf("%x",package[i]);
    qDebug()<<package<<"\n";
    uint16_t cmd;
    QByteArray msg_bag;
    //    qDebug()<<cmd<<"\n";
    data_decoder(package,cmd,msg_bag);
    if(!has_last){
        switch(cmd)
        {
        case 0x30: //需要重新登录
        {
            m_bOnLine = false;
            break;
        }
        case 0x34: //成功注册
        {
            Signal(QString(msg_bag));
            QJsonParseError jsonError;
            QJsonDocument jsonRcvData(QJsonDocument::fromJson(msg_bag, &jsonError));
            if(jsonError.error == QJsonParseError::NoError)
            {
                QJsonObject data = jsonRcvData.object().value("data").toObject();
                QString uid = data.value("UID").toString();
                emit SignalUID(uid);
                emit Signal("Remember your ID:"+uid);
            }
            else{
                emit Signal("error");
            }
            emit SignalSign();
            break;
        }
        case 0x35: //收到登录回复
        {
            QString status;
            qDebug()<<"received\n";
            QJsonParseError jsonError;
            QJsonDocument jsonRcvData(QJsonDocument::fromJson(msg_bag, &jsonError));
            qDebug()<<"ok0\n";
            if(jsonError.error == QJsonParseError::NoError)
            {
                qDebug()<<"ok0\n";
                status = jsonRcvData.object().value("result").toString();
                qDebug()<<"ok1\n";
                if(status == "success")
                {
                    QJsonArray userlist;
                    QJsonArray grouplist;
                    if(jsonRcvData.object().contains("userlist"))
                        userlist = jsonRcvData.object().value("userlist").toArray();
                    if(jsonRcvData.object().contains("grouplist"))
                        grouplist = jsonRcvData.object().value("grouplist").toArray();
                    m_bOnLine = true;
                    int e =  jsonRcvData.object().value("userlist_edition").toInt();
                    emit ServerSendList(userlist,grouplist,e);
                }
                emit Signal(status);
                qDebug()<<"ok2\n";
            }
            else{
                qDebug()<<jsonError.error<<"\n";
            }
            releaselock();
            if(status == "success"){
                emit SignalSign();
            }
            else{
                emit SignalSignError(status);
            }
            break;
        }
        case 0x41: //收到服务器的未读消息
        {
            QJsonParseError jsonError;
            QJsonDocument jsonRcvData(QJsonDocument::fromJson(msg_bag, &jsonError));
            if(jsonError.error == QJsonParseError::NoError)
            {
                QJsonArray up_list;
                QJsonArray up_glist;
                QJsonArray msg_list;
                QJsonArray fmsg_list;
                if(jsonRcvData.object().contains("userlist"))
                    up_list = jsonRcvData.object().value("userlist").toArray();
                if(jsonRcvData.object().contains("grouplist"))
                    up_glist = jsonRcvData.object().value("grouplist").toArray();
                if(jsonRcvData.object().contains("message"))
                {
                    msg_list = jsonRcvData.object().value("message").toArray();
                    if(!msg_list.isEmpty())
                        effect->play();}
                if(jsonRcvData.object().contains("file"))
                {    fmsg_list = jsonRcvData.object().value("file").toArray();
                    if(!fmsg_list.isEmpty() && msg_list.isEmpty())
                        effect->play();}
                emit ServerSendUnreadMsg(msg_list);
                emit ServerSendUnreadFile(fmsg_list);
                emit ServerSendUpdateList(up_list,up_glist);
            }
            break;
        }
        case 0x36: //服务端收到信息，配给id
        {
            emit GetMsgId(msg_bag.toInt());
            break;
        }
        case 0x38: //服务器收到文件请求，配给id
        {
            emit GetMsgId(msg_bag.toInt());
            emit sentfile();
            break;
        }
        case 0x39: //确认服务器收到文件
        {
            emit FileSucccess();
            emit Signal("文件发送成功");
            file->close();
            break;
        }
        case 0x3A: //确认服务器收到文件
        {
            rfile->close();
            if(r_type=="picture"){
                QThread::msleep(10);
                emit showPicture(rfilePath);
            }
            emit Signal("文件下载成功");
            break;
        }
        case 0x3B:
        {
            emit sentfile();
            break;
        }
        default:
        {
            //确认服务器发的是下一个离线文件包则写入本地
            if(cmd == rbag)
            {
                rcvSize += rfile->write(msg_bag);
                emit r_jindu(100*rcvSize/rfileSize,rfileName);
                qDebug()<<rbag<<"\n";
                emit sentRcvRequese(r_info,rbag);
                rbag += 1;
            }
            if(cmd == fbag)
            {
                emit sentfiler();
                break;
            }
        }
        }
    }
    releaselock();
}

//发送信息
void SerSocket::ClientSendingText(const QByteArray &sbag,const uint16_t& cmd)
{
    on_send(data_encoder(sbag,cmd));
    if(this->used && !waitForReadyRead(3000)){
        releaselock();
    }
}

//统一发送函数
quint64 SerSocket::on_send(const QByteArray& msg){
    while(this->used){
        QThread::msleep(320);
    }
    used = true;
    qDebug()<<msg.toHex();
    qDebug()<<msg;
    this->connectToHost(QHostAddress("101.43.221.29"),8888);
    return this->write(msg);
}

//发送文件(头)
void SerSocket::ClientSendingFile(const file_box &fbox)
{
    file_que.enqueue(fbox);
    quint64 len = on_send(data_encoder(fbox.info,0x07));
    if(this->used && !waitForReadyRead(3000)){
        releaselock();
    }
    if(len<=0)
    {
        qDebug()<<"头部信息发送失败 ";
        emit Signal("头部信息发送失败");
    }
}

//发送头像文件头
void SerSocket::ClientSendingIcon(const file_box &fbox)
{
    file_que.enqueue(fbox);
    quint64 len = on_send(data_encoder(fbox.info,0x07));
    if(this->used && !waitForReadyRead(3000)){
        releaselock();
    }
    if(len<=0)
    {
        qDebug()<<"头像信息发送失败 ";
        emit Signal("头像信息发送失败");
    }
}

//打开文件发送第一个文件包
void SerSocket::on_sentfile()
{
    emit Signal("can sent");
    if(!file_que.isEmpty())
    {
        file_box fbox = file_que.dequeue();
        f_uid = fbox.uid;
        f_name = fbox.fname;
        file = new QFile(fbox.fpath);
        fileSize = fbox.sz;
        sendSize = 0;
        if(!file->open(QIODevice::ReadOnly))
        {
            emit Signal("文件打开失败");
            qDebug()<<"文件打开失败";
        }
        fbag = 0x00FF;
        long long maxsz = 1000;
        QByteArray buf = f_uid;
        buf.append(file->read(qMin(maxsz,fileSize)));
        qDebug()<<buf.toHex()<<"\n";
        if(fileSize - sendSize >= maxsz)
        {
            sendSize += maxsz;
            emit jindu(sendSize/fileSize,f_name);}
        else
        {   sendSize = fileSize;
            emit jindu(sendSize/fileSize,f_name);}
        on_send(data_encoder(buf,fbag));
        if(this->used && !waitForReadyRead(3000)){
            releaselock();}
    }
}

//接着传送文件
void SerSocket::on_sentfilebag()
{
    if(sendSize < fileSize)
    {
        long long maxsz = 1000;
        fram.clear();
        QByteArray buf = f_uid;
        qDebug()<<fbag<<"\n";
        fram = file->read(qMin(maxsz,fileSize));
        buf.append(fram);
        if(fileSize - sendSize >= maxsz)
        {
            sendSize += maxsz;
            qDebug() << sendSize << " " << fileSize<<"进度信号";
            emit jindu(sendSize*100/fileSize,f_name);}
        else
        {   sendSize = fileSize;
            qDebug() << sendSize << " " << fileSize<<"进度信号";
            emit jindu(sendSize*100/fileSize,f_name);}
        qDebug()<<buf.toHex()<<"\n";
        qDebug()<<fbag<<"\n";
        //        qDebug()<<buf<<"\n";
        fbag += 1;
        on_send(data_encoder(buf,fbag));
        if(this->used && !waitForReadyRead(3000)){
            releaselock();}}
    else
    {
        QJsonObject uid_bag;
        uid_bag.insert("UID",QString(f_uid));
        QJsonDocument jsonDocument;
        jsonDocument.setObject(uid_bag);
        on_send(data_encoder(jsonDocument.toJson(),0x08));
        emit jindu(sendSize*100/fileSize,f_name);
        if(this->used && !waitForReadyRead(3000)){
            releaselock();}
    }
}

//传入下载命令
void SerSocket::ClientSendingFRequese(const QString &dir, const QString& fname,const QByteArray& info,const int& sz,const QString& type)
{
    QString path(dir);
    rfileSize = sz;
    rfileName = fname;
    rcvSize = 0;
    r_type = type;
    rfilePath = path.append("/").append(fname);
    rfile = new QFile(rfilePath);
    rbag = 0x0800;
    if(!rfile->open(QIODevice::WriteOnly))
    {
        qDebug()<<"write only error";
    }
    qDebug()<<"get message()"<<"\n";
    r_info = info;
    on_send(data_encoder(r_info,0x09));
    if(this->used && !waitForReadyRead(3000)){
        releaselock();
    }
}

//Tools
void SerSocket::ClientConnectToHost(const QString & address, quint16 port)
{
    this->connectToHost(QHostAddress(address), port);
}

void SerSocket::Jump(const QByteArray& bag)
{
    on_send(data_encoder(bag,0x01));
    if(this->used && !waitForReadyRead(3000)){
        releaselock();
    }
}



//是否在线
bool SerSocket::IsOnline()
{
    return m_bOnLine;}
